package mk.jug.academy.controller;

import java.util.logging.Logger;

import mk.jug.academy.factory.EventFactory;
import mk.jug.academy.model.Content;
import mk.jug.academy.model.ContentStatus;
import mk.jug.academy.model.Page;
import mk.jug.academy.model.User;
import mk.jug.academy.service.ContentService;
import mk.jug.academy.service.EventService;
import mk.jug.academy.util.Utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.google.appengine.api.memcache.MemcacheService;

/**
 * View layer coordinator for the Blog functionality in the backend.
 *
 * @author Ice.Penov
 */
@Controller
public class BlogAdminController extends BaseController {
	
	private static final Logger LOG = Logger.getLogger(BlogAdminController.class.getName()); 
	
	//TODO: Externalize this.	
	public static final int itemsPerPage = 8;
	
	private static final String CREATE_BLOG = "admin.blogs.create";
	private static final String LIST_SAVED = "admin.blogs.saved";
	private static final String LIST_INACTIVE = "admin.blogs.inactive";
	private static final String LIST_PUBLISHED = "admin.blogs.published";
	private static final String VIEW_BLOG_ENTRY = "admin.blogs.view";
	private static final String EDIT_BLOG_ENTRY = "admin.blogs.edit";
	
	@Autowired private ContentService contentService;
	@Autowired private EventService eventService;
	@Autowired private MemcacheService memcacheService;
	
	@RequestMapping("/admin/blogs/view.do")
	public String view(final ModelMap map, final @RequestParam("id") Long blogID) {
		return new ControllerContext(map) {
			public String execute() {
				Content blog = contentService.load(blogID);
				map.addAttribute("blog", blog);
				return VIEW_BLOG_ENTRY;
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/saved.do")
	public String listSaved(final ModelMap map, final @RequestParam(value = "page", required = false) Integer p) {
		return new ControllerContext(map) {			
			public String execute() {
				Integer page = p;
				if (page == null) {
					page = 1;
				}
				String email = SecurityContextHolder.getContext().getAuthentication().getName();
				User user = (User) memcacheService.get(email);
				Page<Content> pagedContent = contentService.listSavedAsCreator(page, itemsPerPage, user.getId());
				map.addAttribute("blogs", pagedContent.getItems());
				map.addAttribute("pages", Utils.getPageNumber(itemsPerPage, pagedContent.getTotalCount()));
				map.addAttribute("page", page);
				return LIST_SAVED;
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/published.do")
	public String listPublished(final ModelMap map, final @RequestParam(value = "page", required = false) Integer p) {
		return new ControllerContext(map) {
			@Override
			public String execute() {
				Integer page = p;
				if (page == null) {
					page = 1;
				}
				String email = SecurityContextHolder.getContext().getAuthentication().getName();
				User user = (User) memcacheService.get(email);				
				Page<Content> pagedContent = contentService.listPublishedAsCreator(page, itemsPerPage, user.getId());
				map.addAttribute("blogs", pagedContent.getItems());
				map.addAttribute("pages", Utils.getPageNumber(itemsPerPage, pagedContent.getTotalCount()));
				map.addAttribute("page", page);
				return LIST_PUBLISHED;
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/inactive.do")
	public String listInactive(final ModelMap map, final @RequestParam(value = "page", required = false) Integer p) {
		return new ControllerContext(map) {
			public String execute() {
				Integer page = p;
				if (page == null) {
					page = 1;
				}
				String email = SecurityContextHolder.getContext().getAuthentication().getName();
				User user = (User) memcacheService.get(email);				
				Page<Content> pagedContent = contentService.listDeletedAsCreator(page, itemsPerPage, user.getId());
				map.addAttribute("blogs", pagedContent.getItems());
				map.addAttribute("pages", Utils.getPageNumber(itemsPerPage, pagedContent.getTotalCount()));
				map.addAttribute("page", page);
				return LIST_INACTIVE;
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/deactivate.do")
	public String deactivate(final ModelMap map, final @RequestParam("id") Long id) {
		return new ControllerContext(map) {
			public String execute() {
				Content content = contentService.load(id);
				contentService.delete(content);
				return "redirect:/admin/blogs/published.do";
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/activate.do")
	public String reactivate(final ModelMap map, final @RequestParam("id") Long id) {
		return new ControllerContext(map) {
			public String execute() {
				Content content = contentService.load(id);
				content.setStatus(ContentStatus.PUBLISHED);
				contentService.saveChanges(content);
				return "redirect:/admin/blogs/inactive.do";
			}
		}.result();
	}
	
	
	@RequestMapping("/admin/blogs/create.do")
	public String create(final ModelMap map) {
		return new ControllerContext(map) {
			public String execute() {
				Content blog = new Content();
				blog.setStatus(ContentStatus.DELETED);
				map.addAttribute("blog", new Content());
				return CREATE_BLOG;
			}
		}.result();
	}
	
	@RequestMapping(value = "/admin/blogs/createBlog.do", method = RequestMethod.POST)
	public String processBlogCreation(final ModelMap map, final @ModelAttribute("blog") Content content, final @RequestParam("landURL") String landURL) {
		return new ControllerContext(map) {
			public String execute() {
				String email = SecurityContextHolder.getContext().getAuthentication().getName();
				User user = (User) memcacheService.get(email);
				contentService.save(content, user);
				return "redirect:" + landURL;
			}
		}.result();
	}
	
	@RequestMapping(value = "/admin/blogs/publish.do")
	public String publish(final ModelMap map, final @RequestParam("id") Long id) {
		return new ControllerContext(map) {
			public String execute() {
				Content content = contentService.load(id);
				contentService.publish(content);
				LOG.fine("Blog with id [" + content.getId() + "] was published.");
				eventService.createEvent(EventFactory.createBlogCreationEvent(content));
				return "redirect:/admin/blogs/published.do";
			}
		}.result();
	}
	
	@RequestMapping(value = "/admin/blogs/unpublish.do")
	public String unpublish(final ModelMap map, final @RequestParam("id") Long id) {
		return new ControllerContext(map) {
			public String execute() {
				Content content = contentService.load(id);
				content.setPublishDate(null);
				content.setStatus(ContentStatus.SAVED);
				contentService.saveChanges(content);
				LOG.info("Content [" + content.getTitle() + "] has been unpublished.");
				return "redirect:/admin/blogs/saved.do";
			}
		}.result();
	}	
	
	@RequestMapping(value = "/admin/blogs/saveBlog.do", method = RequestMethod.POST)
	public String processBlogEdit(final ModelMap map, final @ModelAttribute("blog") Content changed, final @RequestParam("id") Long id, final @RequestParam("landURL") String landURL) {
		return new ControllerContext(map) {
			public String execute() {
				Content content = contentService.load(id);
				content.setTitle(changed.getTitle());
				content.setBody(changed.getBody());
				contentService.saveChanges(content);
				LOG.fine("Blog with id [" + content.getId() + "] was saved.");
				return "redirect:" + landURL;
			}
		}.result();
	}
	
	@RequestMapping("/admin/blogs/edit.do")
	public String edit(final ModelMap map, final @RequestParam("id") Long id) {
		return new ControllerContext(map) {
			public String execute() {
				Content blog = contentService.load(id);
				map.addAttribute("blog", blog);
				return EDIT_BLOG_ENTRY;
			}
		}.result();
	}
	
}